using System;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Security.Cryptography.X509Certificates;
using Fleck;
using Fleck.Handlers;
namespace fuzzyKittenVNC
{	
	class Controller {
		private String ws_host;
		private String vnc_host;
		private int vnc_port;
		private int ws_port;
		public Controller(string ws_host,int ws_port,string vnc_host,int vnc_port,bool useTls) {
			this.ws_host = ws_host;
			this.ws_port = ws_port;
			this.vnc_host = vnc_host;
			this.vnc_port = vnc_port;
			this.startServer();
		}
		
		protected void startServer() {
			try {		
				var server = new WebSocketServer("ws://"+ws_host+":"+ws_port);
				
				server.Start(socket =>
				  {
					socket.OnOpen = () => createClient(socket);
					socket.OnError = error => {
						Console.Error.Write(error);
					};
                });
				for(;;) {}
				// the observer shuts down both sockets (vnc, ws) if any of is closed
	//			vnc.register((Observer) connectionObserver);
	//			client.register((Observer)  connectionObserver);
				
			} catch(Exception e) {
				Console.Error.Write(e);
				Logger.log(String.Format("Exception thrown: {0}",e.Message),Logger.LEVEL.ERROR);
				Logger.log(String.Format("Stacktrace {0}",e.StackTrace),Logger.LEVEL.ERROR);
			}
	//		client.disconnect();
	
		}
	
		private void createClient(IWebSocketConnection socket) {
			VNCClient vnc = new VNCClient(vnc_host,vnc_port,false);
			vnc.renderer = new HTML5_Base64Renderer(vnc);

			socket.OnMessage = message => {
				byte[] m = ASCIIEncoding.UTF8.GetBytes(message);
				vnc.requestUpdateFromRequest(m);	
			};
			socket.OnClose = () => vnc.disconnect();
			
			vnc.renderer.sendDelegate += data => {
				socket.Send(data); 
			};
			//vnc.renderer.sendDelegate += client.sendVoid;
			vnc.connect();

		}
	}
	
	class MainClass
	{
		public static string VERSION = "0.1Alpha";
		public static bool DEV_SNAP = true;
		public static void Main (string[] args)
		{
			ArgParser parser = new ArgParser();
			try {
				if(args.Length<2)
					throw new ArgumentException();
				Logger.minLevel = Logger.LEVEL.WARNING;

				parser.addArg("wh","ws_host","string","The host on which to open the websocket");
				parser.addArg("wp","ws_port","string","The port on which to open the websocket");
				parser.addArg("vh","vnc_host","string","The host on which the vnc server is located");
				parser.addArg("cp","vnc_port","string","The port the vnc server is listening on");
				parser.addArg("s","use_tls","bool","Use a secure connection for the websocket");
				parser.addArg("c","cert","string","Certificate to use");
				parser.addArg("p","certpass","string","Certificate pass to use");
				
				string desc = "FuzzyKitten VNC->Websocket adapter"+
					"v{0} - {1}\n" +
					"© 2010-2012 Jannis Moßhammer <mojadev@gmail.com>\n";
				parser.setDescription(String.Format(desc,VERSION,DEV_SNAP ? "Development snapshot" : ""));
				parser.parse(args);
				
                string ws_host = parser.getParam("ws_host",true);
				int ws_port = Convert.ToInt32(parser.getParam("ws_port",true));
				string vnc_host = parser.getParam("vnc_host",true);
				int vnc_port = Convert.ToInt32(parser.getParam("vnc_port",true));
				bool useTLS = (parser.getParam("use_tls",false) == "1");
				if(useTLS) {
					Logger.log(String.Format("Using {0} as TLS certificate", parser.getParam("cert",true)),Logger.LEVEL.INFO);
					WebSocketClient.serverCertificate = new X509Certificate2();
					if(parser.getParam("certpass",false) == "")
						WebSocketClient.serverCertificate.Import(parser.getParam("cert",true));
					else 
						WebSocketClient.serverCertificate.Import(parser.getParam("cert",true),parser.getParam("certpass",true),X509KeyStorageFlags.DefaultKeySet);
				}
				new Controller(ws_host,ws_port,vnc_host,vnc_port,useTLS);
			} catch(Exception e) {
				Logger.log(e.Message,Logger.LEVEL.ERROR);
				parser.printusage();		
			}
		}
		
		public static void printUsage() {
			Logger.log("Usage: fuzzyKittenServer ws_host ws_port vnc_host vnc_port",Logger.LEVEL.ERROR);
		}
	}
}

